/**
 *  Copyright (c) 1997-2013, www.tinygroup.org (luo_guo@icloud.com).
 *
 *  Licensed under the GPL, Version 3.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *       http://www.gnu.org/licenses/gpl.html
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package org.tinygroup.dbf.impl;

import org.tinygroup.dbf.DbfField;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * 工具类
 * Created by luoguo on 2014/4/26.
 */
public final class DbfUtil {
    private DbfUtil() {
    }

    public static final int MAX_MINI_UINT = 256;
    private static final SimpleDateFormat dataFormat = new SimpleDateFormat("yyyyMMdd");


    public static byte[] getBinary(Object value, DbfField field, String encode) throws UnsupportedEncodingException, IOException {
        byte[] result = new byte[0];
        char type = field.getType();
        switch (type) {
            case 'c':
            case 'C':
                result = value.toString().getBytes(encode);
                break;
            case 'd':
            case 'D':
                if(value!=null) result = new SimpleDateFormat("yyyyMMdd").format(((Date)value)).getBytes(encode);
                break;
            case 'n':
            case 'N':
                if(field.getDecimal()==0) {
                    result = String.valueOf((Long) value).getBytes();
                }else{
                    result = String.valueOf((Double) value).getBytes();
                }
                break;
            case 'f':
            case 'F':
                result = String.valueOf((Float) value).getBytes();
                break;
            case 'o':
            case 'O':
                result = String.valueOf((Double) value).getBytes();
                break;
            case 'b':
            case 'B':
                result = String.valueOf((Double) value).getBytes();
                break;
            case 'l':
            case 'L':
                result = DbfUtil.booleanToByteArray((Boolean) value);
                break;
            default:
                throw new IOException("不支持的类型：" + type + ",值为：" + value.toString());
        }

        return result;
    }


    public static Object getValue(String value, DbfField field) throws IOException {
        if (value == null) {
            return null;
        }
        char type = field.getType();
        if (type == 'c' || type == 'C') {
            return value;
        } else if (type == 'n' || type == 'N') {
            if (field.getDecimal() == 0) {
                return getLongValue(value);
            }
            return getDoubleValue(value);
        } else if (type == 'i' || type == 'I') {
            return getLongValue(value);
        } else if (type == 'f' || type == 'F') {
            return getFloatValue(value);
        } else if (type == 'o' || type == 'O') {
            return getDoubleValue(value);
        } else if (type == 'd' || type == 'D') {
            return getDateValue(value);
        } else if (type == 'l' || type == 'L') {
            return getBooleanValue(value);
        }
        throw new IOException("不支持的类型：" + type + ",值为：" + value);
    }

    static Long getLongValue(String value) throws UnsupportedEncodingException {
        if (value.equals("-") || value.equals("")) {
            return null;
        }
        return Long.parseLong(value);
    }

    static Double getDoubleValue(String value) throws UnsupportedEncodingException {
        if (value.equals("-") || value.equals("")) {
            return null;
        }
        return Double.parseDouble(value);
    }

    static Float getFloatValue(String value) throws UnsupportedEncodingException {
        if (value.equals("-") || value.equals("")) {
            return null;
        }
        return Float.parseFloat(value);
    }

    static Boolean getBooleanValue(String value) throws UnsupportedEncodingException {
        return DbfUtil.stringToBoolean(value);
    }

    static Date getDateValue(String value) throws UnsupportedEncodingException {
        try {
            if (value.equals("")) {
                return null;
            }
            return dataFormat.parse(value);
        } catch (ParseException e) {
            throw new RuntimeException(e);
        }
    }
    /**
     * 返回无符号整数
     *
     * @param bytes  字节数组
     * @param start  开始的位置
     * @param length 数字的长度
     * @return
     */
    public static int getUnsignedInt(byte[] bytes, int start, int length) {
        int value = 0;
        for (int i = 0; i < length; i++) {
            value += getUnsignedIntValue(bytes[start + i], i);
        }
        return value;
    }

    /**
     * 日期转换数字节数组
     *
     * @param date
     * @return
     */
    public static byte[] dateToByteArray(int date) {
        byte[] buf = new byte[3];
        buf[0] = (byte) (date / 10000 - 1900);
        buf[1] = (byte) ((date % 10000) / 100);
        buf[2] = (byte) ((date % 100));
        return buf;
    }

    /**
     * 返回指定字节的无符号整数值
     *
     * @param b
     * @param bytePos
     * @return
     */
    public static int getUnsignedIntValue(byte b, int bytePos) {
        int v = 1;
        for (int i = 0; i < bytePos; i++) {
            v = v << 8;
        }
        return getUnsignedInt(b) * v;
    }

    /**
     * byte值转无符号整数
     * @param byteValue
     * @return
     */
    public static int getUnsignedInt(byte byteValue) {
        if (byteValue < 0) {
            return byteValue + MAX_MINI_UINT;
        } else {
            return byteValue;
        }
    }

    /**
     * 整型转Byte数组
     *
     * @param value
     * @param bit
     * @return
     */
    public static byte[] intToByteArray(int value, int bit) {
        byte[] result = new byte[bit];
        for (int i = 0; i < bit; i++) {
            int pos = i << 3;
            result[i] = (byte) (((0xff << pos) & value) >> pos);
        }
        return result;
    }

    /**
     * 长整型转Byte数组
     *
     * @param number
     * @return
     */
    public static byte[] longToByteArray(long number) {
        long temp = number;
        byte[] b = new byte[8];
        for (int i = 0; i < b.length; i++) {
            b[i] = Long.valueOf(temp & 0xff).byteValue();
            temp = temp >> 8;
        }
        return b;
    }

    /**
     * Float值转字节数组
     *
     * @param value
     * @return
     */
    public static byte[] floatToByteArray(float value) {
        int floatToInt = Float.floatToIntBits((Float) value);
        return intToByteArray(floatToInt, 4);
    }

    /**
     * Double值转字节数组
     *
     * @param value
     * @return
     */
    public static byte[] doubleToByteArray(double value) {
        long doubleToLong = Double.doubleToLongBits(value);
        return longToByteArray(doubleToLong);
    }

    /**
     * 布尔值转字节数组
     *
     * @param value
     * @return
     */
    public static byte[] booleanToByteArray(boolean value) {
        return value ? new byte[]{(byte) 't'} : new byte[]{(byte) 'f'};
    }

    /**
     * 字符串转布尔值
     *
     * @param stringValue
     * @return
     */
    public static Boolean stringToBoolean(String stringValue) {
        String value = stringValue.toLowerCase();
        if (value.equals("t") || value.equals("y")) {
            return true;
        }
        if (value.equals("f") || value.equals("n")) {
            return false;
        }
        return null;
    }
}
